#!/bin/bash

#
# init.d/afdsmgrd -- by Dario Berzano <dario.berzano@cern.ch>
#
# This file is part of afdsmgrd -- see http://code.google.com/p/afdsmgrd
#
# This script is conform to the LSB specifications and it is compatible with
# the chkconfig custom header format. It can also be run by an unprivileged
# user and without being installed system-wide.
#

#
# chkconfig header
#

# chkconfig: 2345 99 0
# description: afdsmgrd, which stands for Analysis Facility Dataset Manager
#              Daemon, is a ROOT-based daemon that scans the stored datasets in
#              order to issue the actual data staging
# processname: afdsmgrd
# pidfile: /var/run/afdsmgrd.pid

#
# LSB header
#

### BEGIN INIT INFO
# Provides: afdsmgrd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Short-Description: Dataset manager for PROOF-based AFs
# Description: afdsmgrd, which stands for Analysis Facility Dataset Manager
#              Daemon, is a ROOT-based daemon that scans the stored datasets in
#              order to issue the actual data staging
### END INIT INFO

#
# External libraries and global variables
#

# Basename of the script, wrt invoking command (i.e. no symlinks resolved)
BASENAME=`basename "$0"`

# Get the configuration variables from the first configuration file found
declare -a CONF_FILES
CONF_FILES=(
  "@DIR_ETC@/sysconfig/$BASENAME" \
  "@DIR_ETC@/default/$BASENAME" \
  "/etc/sysconfig/$BASENAME" \
  "/etc/default/$BASENAME" \
  "$HOME/.$BASENAME.cf"
)

CF_FOUND=0
for CF in "${CONF_FILES[@]}"; do
  if [ -r "$CF" ]; then
    CF_FOUND=1
    source "$CF"
    break
  fi
done

# No configuration file found?
if [ "$CF_FOUND" == 0 ]; then
  echo "No configuration file found for $BASENAME amongst (in order):"
  for CF in "${CONF_FILES[@]}"; do
    echo " * $CF"
  done
  exit 1
fi

# Full path of program
export PROG="$AFDSMGRD_PROG"

# Silently fails if program is missing (for spurious init.d scripts)
[ -x "$PROG" ] || exit 0

# Basename of program
export BASEPROG=`basename "$PROG"`

# File that holds the PID
export PIDFILE="$AFDSMGRD_PIDFILE"

# Log file
export LOGFILE="$AFDSMGRD_LOGFILE"

# Log dir
export LOGDIR="$AFDSMGRD_LOGDIR"

# Configuration file
export CONF="$AFDSMGRD_CONF"

# Daemon user
export SUSER="$AFDSMGRD_USER"

# Log level
export LOG_LEVEL="$AFDSMGRD_LOGLEVEL"

# Temporary directory (hardcoded)
export TEMPDIR="/tmp/afdsmgrd"

# Grace time before "kill -9", in seconds
export GRACEKILL_SEC=10

#
# Functions
#

# Auxiliary messaging function: normal echo
function Msg() {
  echo "$@"
}

# Auxiliary messaging function: begin of operation
function MsgBegin() {
  echo -n "$@: "
}

# Auxiliary messaging function: end of operation
function MsgEnd() {
  local STATUS
  [ "$1" == 0 ] && \
    STATUS="\033[1;32mOK\033[m" || \
    STATUS="\033[1;31mfailed\033[m"
  shift
  if [ "$*" != "" ]; then
    echo -e "$STATUS ($@)"
  else
    echo -e "$STATUS"
  fi
}

# Echoes the PID of the program if running; empty string otherwise
function GetPid() {
  local PID=`cat "$PIDFILE" 2> /dev/null`
  kill -0 "$PID" 2> /dev/null && echo $PID
}

# Tries to stop, then kills the specified PID
function StopKill() {
  local PID="$1"
  local I
  kill -15 "$PID" 2> /dev/null
  for ((I=0; $I<$GRACEKILL_SEC; I++)); do
    sleep 1
    kill -0 "$PID" 2> /dev/null
    [ $? != 0 ] && return 0
  done
  kill -9 "$PID" 2> /dev/null
  sleep 1
  kill -0 "$PID" 2> /dev/null && return 1 || return 0
}

# Cleanup of daemon's temporary directory: called on startup and shutdown. This
# is the first function to customize
function Cleanup() {
  rm -rf "$TEMPDIR"
  return $?
}

# This is the second function to edit: it contains the custom commands to
# effectively launch the daemon
function LaunchDaemon() {

  # Creates temporary directory
  Cleanup
  mkdir -p "$TEMPDIR"
  chmod -R u=rwX,g=rX,o=rX "$TEMPDIR" > /dev/null 2>&1
  chown -R "$SUSER" "$TEMPDIR" > /dev/null 2>&1

  # Change permissions of log directory
  mkdir -p "$LOGDIR" > /dev/null 2>&1
  touch "$LOGFILE" > /dev/null 2>&1
  chmod -R u=rwX,g=rX,o=rX "$LOGDIR" > /dev/null 2>&1
  chown -R "$SUSER" "$LOGDIR" > /dev/null 2>&1

  # Creates directory for pidfile (if not exists)
  mkdir -p $(dirname "$PIDFILE")

  # This is a setuid program: for security reasons, LD_LIBRARY_PATH is not
  # inherited in the environment inside the daemon
  ( export LD_LIBRARY_PATH="$ROOTSYS/lib:$AFDSMGRD_LIBS:$LD_LIBRARY_PATH" ; \
    "$AFDSMGRD_PROG" -b -u "$SUSER" -p "$PIDFILE" -c "$CONF" -d "$LOG_LEVEL" \
    -l "$LOGFILE" -e "$AFDSMGRD_LIBEXEC" )

  return $?
}

# Starts the daemon (if not running)
function Start() {
  local PID RETVAL
  MsgBegin "Starting $BASEPROG"
  PID=`GetPid`
  if [ "$PID" == "" ]; then
    LaunchDaemon
    RETVAL=$?
    MsgEnd $RETVAL
  else
    MsgEnd 1 "already running with PID=$PID"
    RETVAL=1
  fi
  return $RETVAL
}

# Stops the daemon
function Stop() {
  local PID RETVAL
  MsgBegin "Stopping $BASEPROG"
  PID=`GetPid`
  if [ "$PID" == "" ]; then
    MsgEnd 0 "not running"
    RETVAL=0
  else
    StopKill $PID
    RETVAL=$?
    if [ $RETVAL == 0 ]; then
      rm -f "$PIDFILE"
      Cleanup
    fi
    MsgEnd $RETVAL
  fi
  return $RETVAL
}

# Status of the daemon; returns 0 if running, nonzero otherwise
function Status() {
  local PID
  PID=`GetPid`
  if [ "$PID" == "" ]; then
    Msg "$BASEPROG is not running"
    return 1
  else
    Msg "$BASEPROG is running with PID=$PID"
    return 0
  fi
}

# Last lines of log
function ShowLog() {
  Status
  if [ $? == 0 ]; then
    echo "Showing last lines of $LOGFILE with tail -f (abort with Ctrl+C):"
    tail -f "$LOGFILE"
  fi
}

#
# Entry point
#

case "$1" in
  start)
    Start
    exit $?
  ;;
  stop)
    Stop
    exit $?
  ;;
  status)
    Status
    exit 0
  ;;
  log)
    ShowLog
    exit 0
  ;;
  restart|condrestart|reload)
    Stop && Start
    exit $?
  ;;
  sysconfig)
    echo "Using startup configuration file: $CF"
    exit 0
  ;;
  #drain)
  # to be implemented
  #;;
  *)
    echo  "Usage: `basename $0` {start|stop|restart|condrestart|reload|status|sysconfig|log}"
    exit 1
  ;;
esac
